// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Actors;
using System.Threading.Tasks;

namespace ActorFramework.Fakebook
{
    public class NewsFeed : IDisposable
    {
        private FabricActorClient _actorClient;
        private String _accountName;

        private const String ApplicationType = "fabric:/actor/fakebook";  // Do not put a / on the end here.
        private const String NewsFeedActorName = ApplicationType + "/NewsFeed";

        public NewsFeed(String fabricAddress, String accountName, bool connectThroughGateway = false, int numReplicas = 2)
        {
            Contract.Requires(numReplicas >= 1);

            //Uri actorUri = new Uri(ApplicationType + "/" + accountName + ActorTypeSuffix);
            Uri actorUri = new Uri(ApplicationType + "/NewsFeed");
            _accountName = accountName;

            _actorClient = FabricActorClient.CreateOrConnectToActor(fabricAddress, ApplicationType, actorUri,
                                                                    "EmptyActorReplica", connectThroughGateway, numReplicas,
                                                                    FakebookPerson.NumPartitions, accountName);

            // Hack - update assembly
            EnsureAssemblyIsUpToDate();

            _actorClient.CallMethod("TryConstruct", new Object[] { _accountName });
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (_actorClient != null)
                {
                    _actorClient.Dispose();
                    _actorClient = null;
                }
            }
        }

        /*
        public void Destroy()
        {
            FabricActorClient.DeleteActor(_actorClient.FabricUri.ToString(), GetNewsfeedActorName(_accountName));
            Dispose();
        }
         */

        /*
        public static String GetNewsfeedActorName(String accountName)
        {
            //return ApplicationType + "/" + accountName + ActorTypeSuffix;
            return NewsFeedActorName;
        }
        */

        /*
        public static String GetNewsPostsListName(String accountName)
        {
            return accountName + "_NewsPosts";
        }
        */

        public static String NewsPostsListName {
            get { return "fabric:/actor/list/NewsPosts"; }
        }

        private void EnsureAssemblyIsUpToDate()
        {
            String binariesDir = Path.Combine(Environment.CurrentDirectory, "..\\..\\..");
            FabricActorClient client = _actorClient;

            String newsfeedActorPath = Path.Combine(binariesDir, "NewsfeedActor\\bin\\debug\\NewsfeedActor.dll");
            Assembly newsfeedActorAssembly = Assembly.LoadFrom(newsfeedActorPath);
            client.AddAssembly(newsfeedActorAssembly.FullName, File.ReadAllBytes(newsfeedActorAssembly.Location));
        }

        public IDisposable Subscribe(IObserver<ActorEvent> observer)
        {
            return _actorClient.Subscribe("NewNews", observer);
        }
    }
}
